SQ, PQ, and BQ: three points on the compression/accuracy curve
Qdrant's original quantization trio sits at three different points on the compression-vs-accuracy curve. Scalar quantization (SQ) maps each float32 dimension to an int8 value using a linear scale, typically clipped at a quantile to handle outliers. It gives a fixed 4x compression, and because 256 levels per dimension is a fairly fine grid, the accuracy loss is small - often under one point of recall@10 on real embeddings. It is the safe default and the first thing to try. Product quantization (PQ) splits the vector into subspaces, runs k-means on each subspace to learn a codebook of centroids, and stores the centroid index for each subspace instead of the raw values. Compression depends on the number of subspaces and the codebook size: with 8-bit codes and 96 subspaces on a 768-dim vector, you get roughly 32x compression. The accuracy loss is larger because the codebook is a coarse approximation, but PQ can be tuned via the number of subspaces and centroids to land anywhere on the curve. Binary quantization (BQ) reduces each dimension to a single bit - essentially the sign - giving 32x compression. It is the most aggressive and the most lossy, and it is only viable with oversampling and rescoring to recover accuracy.
The mechanism behind the accuracy differences is how much information each scheme preserves about the relative geometry. SQ preserves the ordering of values along each dimension but loses magnitude precision; distances between quantized vectors are close to the true distances because the error per dimension is small and roughly unbiased. PQ preserves the cluster membership in each subspace but loses the position within the cluster; distances are approximated by the distance between centroids, which is a coarser approximation but still captures the dominant structure. BQ preserves only the sign, which is enough to capture the direction of the vector but throws away all magnitude information. For cosine similarity on normalized vectors, BQ is surprisingly effective because direction is what matters, which is why it works well on high-dimensional embeddings. For Euclidean distance on unnormalized vectors, BQ is much weaker. The other dimension of difference is the interaction with HNSW: SQ and PQ quantized vectors are typically used for the distance computations during graph traversal, while full-precision vectors are kept for rescoring. BQ almost always requires rescoring because the binary distance alone is too noisy to rank a candidate set reliably.
Scalar (int8): 4x compression, minimal accuracy loss, no codebook training, works on any vector size. The safe default.
Product (PQ): 8x-64x compression depending on subspaces and codebook size, moderate accuracy loss, requires k-means training on the data, best when memory is very tight.
Binary (BQ): 32x compression, largest accuracy loss, requires oversampling and rescoring, best for high-dimensional (>= 1024) normalized embeddings used with cosine distance.
All three can coexist with HNSW; the choice is orthogonal to the graph parameters and can be changed without rebuilding the graph in most cases.
The trade-off is straightforward: SQ is the safest and gives the least compression; BQ gives the most compression and requires the most care; PQ sits in between and is the most tunable but also the most complex to configure. My default order of experiments is SQ first (it almost always works and costs nothing to try), then BQ with oversampling and rescoring if I need more compression and the vectors are high-dimensional and normalized, and PQ only if BQ is not accurate enough and I need something between 4x and 32x. The common mistake is treating PQ as strictly better than SQ because it compresses more. It does not - PQ's accuracy depends heavily on the data distribution and on the codebook training, and on some datasets PQ at 16x compression is worse than SQ at 4x. Another common mistake is enabling BQ without oversampling and rescoring and then concluding BQ is unusable. BQ without rescoring is not a fair test of the scheme. Version note: Qdrant has added sub-byte and asymmetric quantization options in recent releases, so the three-way comparison here is the classic baseline rather than the full current menu.
Version-dependent: the CompressionRatio enum values for PQ and the exact behavior of QuantizationSearchParams have evolved. Binary quantization in particular was added relatively late and has continued to gain options (e.g. sub-byte variants) in subsequent releases. If you are comparing schemes, always benchmark on your own data and your own Qdrant version rather than relying on published compression ratios or recall numbers from a different release.
You have a 1M-vector collection and 4 GB of RAM. Which quantization scheme do you pick and why?
A teammate enables BQ and reports recall dropped to 0.6. What did they probably forget to do, and how would you fix it?
You need to fit a 50M-vector collection on a machine with 32 GB of RAM. Compare SQ, PQ, and BQ for this constraint and recommend one with justification.
You try PQ on your data and recall is worse than SQ at the same effective memory budget. Explain why that can happen and whether it means PQ is the wrong choice.
Design a benchmark that fairly compares SQ, PQ, and BQ on your corpus, controlling for memory, latency, and recall. What are the confounding variables you need to hold fixed?
You are serving a collection where some queries are known to be easy and some hard. Propose a scheme that uses different quantization strategies for different query types and explain how you would route between them.
Derive the expected recall of BQ with oversampling factor k and rescoring as a function of the per-dimension sign error rate. What does the model predict about the optimal k and where does it break down?
You must support both a high-recall enterprise tier and a low-cost free tier on the same collection. Design a quantization and index configuration that serves both without duplicating storage.